package base.loader {
    import flash.net.*
    import flash.events.*;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
	import flash.utils.ByteArray;

    public class URLLoaderExt extends URLLoader {
    	private var arrFunctionToCall: Array;        
        private var timerTimeout:Timer;
    	
    	function URLLoaderExt() {}
    	
        public function sendAndLoad(serverUrl:String, arrParams: Array, arrFunctionToCall:Array, isGetPost:Number = 1, timeTimeout:Number = 30000, addRandomValue: Boolean = true, arrObjHeader: Array = null, variables: * = null, isTextBinaryVariables: uint = 0): void {
			this.arrFunctionToCall = arrFunctionToCall;
            this.defineTimeoutForNetOperation(timeTimeout);
            this.addListeners();
			this.dataFormat = [URLLoaderDataFormat.TEXT, URLLoaderDataFormat.BINARY, URLLoaderDataFormat.VARIABLES][isTextBinaryVariables];
            var request:URLRequest = new URLRequest(serverUrl);
			if (arrObjHeader == null) {
                arrObjHeader = [];
            }
			//{name: "pragma", value: "no-cache"}
			var i: uint;
			for (i = 0; i < arrObjHeader.length; i++) {
                var objHeader: Object = arrObjHeader[i];
				var header:URLRequestHeader = new URLRequestHeader(objHeader.name, objHeader.value);
				request.requestHeaders.push(header);
            }
			if (variables == null) {
				variables = new URLVariables();
				if (arrParams == null) {
					arrParams = [];
				}
				for (i = 0; i < arrParams.length; i++) {
					var param: Array = arrParams[i];
					variables[param[0]] = param[1];
				}
				if (addRandomValue) {
					variables["random"] = Math.random() * 10000000;
				}
			}
            request.data = variables;
            request.method = [URLRequestMethod.GET, URLRequestMethod.POST][isGetPost];
            try {
                this.load(request);
            } catch (error:Error) {
                trace("Unable to load requested document.");
                this.arrFunctionToCall[0].apply(this.arrFunctionToCall[1], new Array(false, error).concat(this.arrFunctionToCall[2]));
            }
        }
        
        private function timeoutHandler(event:TimerEvent):void {
            trace("Timeout");
            this.close();
            this.arrFunctionToCall[0].apply(this.arrFunctionToCall[1], new Array(false, event).concat(this.arrFunctionToCall[2]));
        }
    	
    	private function defineTimeoutForNetOperation(timeTimeout:Number = 30000): void {
            this.timerTimeout = new Timer(timeTimeout, 1);
            this.timerTimeout.addEventListener("timer", this.timeoutHandler);
            this.timerTimeout.start();
    	}
    	
        private function addListeners():void {
            if (!this.hasEventListener(Event.COMPLETE))
                this.addEventListener(Event.COMPLETE, this.completeHandler);
            if (!this.hasEventListener(SecurityErrorEvent.SECURITY_ERROR))
                this.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
            if (!this.hasEventListener(IOErrorEvent.IO_ERROR))
                this.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
        }

		private function removeListeners(): void {
            if (this.hasEventListener(Event.COMPLETE))
                this.removeEventListener(Event.COMPLETE, this.completeHandler);
            if (this.hasEventListener(SecurityErrorEvent.SECURITY_ERROR))
                this.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
            if (this.hasEventListener(IOErrorEvent.IO_ERROR))
                this.removeEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
        }
		
        private function completeHandler(event:Event):void {
            this.clearElements();
			var vars: *;
			try {
				if (this.dataFormat == URLLoaderDataFormat.TEXT) vars = String(event.target.data) //new XML(event.target.data);
				else if (this.dataFormat == URLLoaderDataFormat.BINARY) vars = ByteArray(event.target.data);
				else if (this.dataFormat == URLLoaderDataFormat.VARIABLES) vars = new URLVariables(event.target.data);
			} catch (error:Error) {  
				vars = String(event.target.data)
			}
            this.arrFunctionToCall[0].apply(this.arrFunctionToCall[1], new Array(true, vars).concat(this.arrFunctionToCall[2]));
        }

        private function securityErrorHandler(event:SecurityErrorEvent):void {
            trace("securityErrorHandler: " + event);
            this.clearElements();
            this.arrFunctionToCall[0].apply(this.arrFunctionToCall[1], new Array(false, event).concat(this.arrFunctionToCall[2]));
        }


        private function ioErrorHandler(event:IOErrorEvent):void {
            trace("ioErrorHandler: " + event);
            this.clearElements();
            this.arrFunctionToCall[0].apply(this.arrFunctionToCall[1], new Array(false, event).concat(this.arrFunctionToCall[2]));
        }
	
    	public function generateRandomPassword(countChars: uint): String {
    		var numChar: uint;
    		var strPassword: String = "";
    		for (var i: uint = 0; i < countChars; i++) {
    			do {
    				numChar = Math.round(Math.random() * 255);
    			} while (!(((numChar >= 65) && (numChar <= 90)) || ((numChar >= 48) && (numChar <= 57)) || ((numChar >= 97) && (numChar <= 122))));
    			strPassword += String.fromCharCode(numChar);
    		}
    		return strPassword;
    	}
		
		private function clearElements(): void {
			this.timerTimeout.stop();
			this.removeListeners();
		}
		
		public function destroy(): void {
			if (this.timerTimeout.running) {
				this.clearElements();
				this.close();
			}
		}
		
		public static function parseXMLToObject(xmlNode: *): Object {
			var obj: Object = {};
			var xmlListAttributes: XMLList = xmlNode.@*;
			for (var i: uint = 0; i < xmlListAttributes.length(); i++)
				obj[String(xmlListAttributes[i].name())] = xmlListAttributes[i];
			var xmlListElements: XMLList = xmlNode.*;
			for (i = 0; i < xmlListElements.length(); i++) {
				var nameXMLListElement: String = String(xmlListElements[i].name());
				if (nameXMLListElement == "null") nameXMLListElement = "text"; //element tekstowy
				obj[nameXMLListElement] = xmlListElements[i];
			}
			for (var attr: String in obj) {
				if ((!isNaN(Number(obj[attr]))) && (obj[attr] != "")) {
					if (Number(obj[attr]) == uint(obj[attr])) obj[attr] = uint(obj[attr]);
					else obj[attr] = Number(obj[attr]);
				} else {
					obj[attr] = String(obj[attr]).split("\\n").join("\n");	
					obj[attr] = String(obj[attr]).split("\r").join("");
				}
			}
			return obj;
		}
		
    }
}

/*
example:

import base.URLLoaderExt;
this.urlLoaderExt = new base.URLLoaderExt();
var arrApplyFunction = new Array(2);
arrApplyFunction[0] = function(isLoaded, nodeAllowedDomainsForGames) {
	trace("isLoaded:" + isLoaded)
	trace("nodeAllowedDomainsForGames:" + nodeAllowedDomainsForGames)
}
arrApplyFunction[1] = this;
//this.urlLoaderExt.sendAndLoad("http://urllock.dev.spillgroup.eu:8080/comp-serv/xml/allowedDomainsForGames.xml", [], arrApplyFunction, 1, 60000, false);
this.urlLoaderExt.sendAndLoad("http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/england/rss.xml", [], arrApplyFunction, 1, 60000, false);

*/